//
//  WSQHttpRequest.m
//  WSQOCTools
//
//  Created by 翁胜琼 on 2019/1/18.
//  Copyright © 2019 Dev John. All rights reserved.
//

#import "WSQHttpRequest.h"
#import <AFNetworking/AFNetworking.h>
#import "NSString+Date.h"
#import "NSString+Hash.h"
#import "WSQBaseConfig.h"
#import <SVProgressHUD/SVProgressHUD.h>

/***
 LOGIN_ERROR(42, "用户名或密码不对"),
 MISS_TOKEN(41, "user_token失效"),
 REQUEST_OVERTIME(43, "请求超时"),
 REPEAT_REQUEST(45, "重复请求"),
 SING_ERROR(46, "签名校验失败"),
 SUCCESS(0, "成功"),
 RQUEST_ERROR(100, "请求错误"),
 MISS_SIGN(102, "缺少签名"),
 MISS_PARAM(103, "缺少参数"),
 SERVER_ERROR(200, "服务器出错"),
 SEVER_NOT(201, "服务器不可用"),
 SEVER_RESTART(202, "服务器正在重启"),
 USER_EXIT(203, "该用户已存在"),
 WRITE_USERNAME(204, "请输入用户名"),
 WRITE_PASSWORD(206, "请输入密码"),
 CHECK_AGAIN(207, "请重新校验"),
 USER_EXCEPTION(208, "用户异常");
 */
typedef NS_ENUM(NSUInteger, WSQHttpRequestMethod) {
    WSQHttpRequestMethodGET = 0,
    WSQHttpRequestMethodPUT = 1,
    WSQHttpRequestMethodPOST = 2,
    WSQHttpRequestMethodDELETE = 3
};


@implementation WSQHttpRequest

// MARK: - POST
+ (void)POST:(NSString *)url parameters:(NSDictionary *)parameters token:(HttpRequestTokenType)tokenType success:(void (^)(id _Nonnull response))success failure:(void (^)(NSError * _Nonnull error, NSInteger code))failure
{
    AFHTTPSessionManager *manager;
    // 中文转码
    NSString *completeUrlStr = [self getCompleteUrlWithPath:url];
    
    NSLog(@"======POST 请求地址========%@",completeUrlStr);
    NSLog(@"======请求参数========%@",parameters);
    
    // 创建 manager,注意此方法中配置了请求头信息
    manager = [self createManagerWithToken:tokenType params:parameters];
    
    //请求管理
    [manager POST:completeUrlStr parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodPOST task:task
                     responseObject:responseObject success:success];
        
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodPOST task:task error:error failure:failure];
        
    }];
}

// MARK: - GET
+ (void)GET:(NSString *)url
 parameters:(NSDictionary *)parameters
      token:(HttpRequestTokenType)tokenType
    success:(void (^)(id _Nonnull response))success
    failure:(void (^)(NSError * _Nonnull error, NSInteger code))failure
{
    AFHTTPSessionManager *manager;
    
    // 中文转码
    NSString *completeUrlStr = [self getCompleteUrlWithPath:url];
    
    NSLog(@"======GET 请求地址========%@",completeUrlStr);
    NSLog(@"======请求参数========%@",parameters);
    
    // 创建 manager,注意此方法中配置了请求头信息
    manager = [self createManagerWithToken:tokenType params:parameters];
    
    [manager GET:completeUrlStr parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodGET task:task
                     responseObject:responseObject success:success];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodGET task:task error:error failure:failure];
        
    }];
}

// MARK: - PUT
+ (void)PUT:(NSString *)url
 parameters:(NSDictionary *)parameters
      token:(HttpRequestTokenType)tokenType
    success:(void (^)(id _Nonnull response))success
    failure:(void (^)(NSError * _Nonnull error, NSInteger code))failure
{
    AFHTTPSessionManager *manager;
    
    // 中文转码
    NSString *completeUrlStr = [self getCompleteUrlWithPath:url];
    
    NSLog(@"======PUT 请求地址========%@",completeUrlStr);
    NSLog(@"======请求参数========%@",parameters);
    
    // 创建 manager,注意此方法中配置了请求头信息
    manager = [self createManagerWithToken:tokenType params:parameters];
    
    [manager PUT:completeUrlStr parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodPUT task:task
                     responseObject:responseObject success:success];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodPUT task:task error:error failure:failure];
        
    }];
}

// MARK: - GELETE
+ (void)DELETE:(NSString *)url
    parameters:(NSDictionary *)parameters
         token:(HttpRequestTokenType)tokenType
       success:(void (^)(id _Nonnull response))success
       failure:(void (^)(NSError * _Nonnull error, NSInteger code))failure
{
    AFHTTPSessionManager *manager;
    
    // 中文转码
    NSString *completeUrlStr = [self getCompleteUrlWithPath:url];
    
    NSLog(@"======DELETE 请求地址========%@",completeUrlStr);
    NSLog(@"======请求参数========%@",parameters);
    
    // 创建 manager,注意此方法中配置了请求头信息
    manager = [self createManagerWithToken:tokenType params:parameters];
    manager.requestSerializer.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", nil];

    [manager DELETE:completeUrlStr parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodDELETE task:task
                     responseObject:responseObject success:success];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        [self handleResponseWithUrl:completeUrlStr Method:WSQHttpRequestMethodDELETE task:task error:error failure:failure];
        
    }];
}

// MARK: - Private Method
// 网络请求失败统一处理
+ (void)handleResponseWithUrl:(NSString *)url
                       Method:(WSQHttpRequestMethod)method
                         task:(NSURLSessionDataTask * _Nullable)task
                        error:(NSError *)error
                      failure:(void (^)(NSError * _Nonnull error, NSInteger code))failure
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible = false;
    });
    // 将请求方式枚举转为字符串
    NSString *methodStr = [self getRequestStringWithMethod:method];
    
    NSLog(@"%@ 请求失败:URL:%@    error信息：%@",methodStr,url,error);
    NSInteger statusCode = 0;           // 状态码
    NSDictionary *responseHeader;       // 响应头
    
    if ([task.response isKindOfClass:[NSHTTPURLResponse class]])
    {
        NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
        responseHeader = response.allHeaderFields;
        statusCode = response.statusCode;
    }
    
    if (failure) {
        failure(error , statusCode);
        [SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"网络请求失败，请检查网络-(%ld)",(long)statusCode]];
    } else {
        [SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"网络请求失败，请检查网络-(%ld)",(long)statusCode]];
    }
}

// 网络请求成功统一处理
+ (void)handleResponseWithUrl:(NSString *)url
                       Method:(WSQHttpRequestMethod)method
                         task:(NSURLSessionDataTask * _Nullable)task
               responseObject:(id)responseObject
                      success:(void (^)(id _Nonnull response))success
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible = false;
    });
    // 将请求方式枚举转为字符串
    NSString *methodStr = [self getRequestStringWithMethod:method];
    
    NSDictionary *responseDic = [NSDictionary dictionaryWithDictionary:responseObject];
    
    NSLog(@"%@ 请求成功:URL:%@ 返回结果:%@",methodStr,url,responseDic);
    
    success(responseDic);
}

// 获取网络请求方式字符串
+ (NSString *)getRequestStringWithMethod:(WSQHttpRequestMethod)method
{
    NSString *methodStr;
    switch (method) {
        case WSQHttpRequestMethodGET:
        {
            methodStr = @"GET";
        }
            break;
        case WSQHttpRequestMethodPUT:
        {
            methodStr = @"PUT";
        }
            break;
        case WSQHttpRequestMethodPOST:
        {
            methodStr = @"POST";
        }
            break;
        case WSQHttpRequestMethodDELETE:
        {
            methodStr = @"DELETE";
        }
            break;
    }
    return methodStr;
}

// 获取完整 Url
+ (NSString *)getCompleteUrlWithPath:(NSString *)path
{
    NSString *utf8Url = [path stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]];
    NSString *completeUrlStr = [NSString stringWithFormat:@"%@%@",[WSQBaseConfig shared].apiUrl,utf8Url];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible = true;
    });
    
    return completeUrlStr;
}

// 初始化网络请求管理类
+ (AFHTTPSessionManager *)createManagerWithToken:(HttpRequestTokenType)tokenType params:(NSDictionary *)parameters
{
    NSString *timestamp = [self getTimestamp];
    // 为网络请求参数签名
    NSString *nonceStr = [self getRandomNonceWithTimestamp:timestamp];
    NSString *signedStr = [self encryptWithParams:parameters token:tokenType timestamp:timestamp nonce:nonceStr];
    
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    config.timeoutIntervalForRequest = 10;
    dict[@"sign"] = signedStr;
    dict[@"timestamp"] = [self getTimestamp];
    dict[@"nonce"] = nonceStr;
    dict[@"Authorization"] = [self getTokenWithTokenType:tokenType];
    dict[@"os"] = @"iOS";
    dict[@"curVer"] = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    
    //    NSLog(@"===sign:%@", dict[@"sign"]);
    //    NSLog(@"===nonce:%@",dict[@"nonce"]);
    //    NSLog(@"===timestamp:%@", dict[@"timestamp"]);
    //    NSLog(@"===Authorization:%@", dict[@"Authorization"]);
    
    config.HTTPAdditionalHeaders = dict;
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:config];
    //更改执行的线程
    manager.completionQueue = dispatch_get_global_queue(0, 0);
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    AFJSONResponseSerializer *response = [AFJSONResponseSerializer serializer];
    // 移除Null
    response.removesKeysWithNullValues = true;
    manager.responseSerializer = response;
    
    return manager;
}


// 产生随机字符串 规则 timestamp + UUID
+ (NSString *)getRandomNonceWithTimestamp:(NSString *)timestamp
{
    NSString *uuidString = [[NSUUID UUID] UUIDString];
    NSString *nonceString = [timestamp stringByAppendingString:uuidString].md5String;
    
    return nonceString;
}

// 获取时间戳 精确到 second
+ (NSString *)getTimestamp
{
    NSInteger timeInterval = [NSString getCurrentTimeinterval];
    NSString *timestamp = [NSString stringWithFormat:@"%ld",(long)timeInterval];
    
    return timestamp;
}

+ (NSString *)encryptWithParams:(NSDictionary *)params token:(HttpRequestTokenType)tokenType
                      timestamp:(NSString *)timestamp nonce:(NSString *)nonce
{
    NSString *privateKey = @"";
    NSString *token = [self getTokenWithTokenType:tokenType];
    NSString *signedStr =  [self getSignStringWith:params timeStamp:timestamp token:token privateKey:privateKey nonce:nonce];
    
    return signedStr;
}

// 对参数进行签名
+ (NSString *)getSignStringWith:(NSDictionary *)params timeStamp:(NSString *)timeStamp
                          token:(NSString *)token  privateKey:(NSString *)key nonce:(NSString *)nonce
{
    // 获取排序拼接的参数字符串
    NSString *paramsString = [self appendingParamsWithDic:params];
    // 获取拼接之后的字符串
    NSString *unsignString = [[[[paramsString stringByAppendingString:timeStamp] stringByAppendingString:token] stringByAppendingString:nonce] stringByAppendingString:key];
    
    // 获取 MD5之后的字符串
    NSString *signString = [unsignString md5String];
    // 签名字符串转大写
    NSString *uppercaseSignString = [signString uppercaseString];
    
    return uppercaseSignString;
}

// 参数根据 key 排序之后转为字符串
+ (NSString *)appendingParamsWithDic:(NSDictionary *)params
{
    NSMutableString *paramsStringAfterSort = [NSMutableString string];
    NSArray *allKeys = params.allKeys;
    
    // 排序
    NSArray *sortedKeysArray = [allKeys sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        NSComparisonResult result = [obj1 compare:obj2];
        return result==NSOrderedDescending;//NSOrderedAscending 倒序
    }];
    
    for (NSString *key in sortedKeysArray) {
        id value = [self appendingStringWithValue:params[key]];
        
        [paramsStringAfterSort appendFormat:@"%@=%@&",key,value];
    }
    
    NSString *finalParamstr = paramsStringAfterSort;
    if (paramsStringAfterSort.length > 0)
    {
        finalParamstr = [paramsStringAfterSort substringToIndex:paramsStringAfterSort.length - 1];
    }
    
    return finalParamstr;
    
}

// 获取 token
+ (NSString *)getTokenWithTokenType:(HttpRequestTokenType)tokenType
{
    NSString *token;
    NSString *accessToken = [WSQBaseConfig shared].accessToken;
    NSString *anonymousToken = [WSQBaseConfig shared].anonymousToken;
    switch (tokenType) {
        case HttpRequestTokenTypeAnonymous:
        {
            token = anonymousToken;
        }
            break;
        case HttpRequestTokenTypeNone:
        {
            token = @"";
        }
            break;
        case HttpRequestTokenTypeAccessToken:
        {
            token = accessToken;
        }
            break;
        case HttpRequestTokenTypeNeutralToken: {
            token = accessToken.length >0? accessToken:anonymousToken;
            break;
        }
    }
    
    return token;
}

// 字典转字符串
+ (NSString *)dictionaryToString:(NSDictionary *)params
{
    NSMutableString *appendedString = [NSMutableString string];
    
    if (params.count == 0) // 无数据
    {
        [appendedString appendString:@"{}"];
    }else if (params.count == 1)   // 单条数据
    {
        [appendedString appendFormat:@"{%@:%@}",params.allKeys.firstObject,[self appendingStringWithValue:params.allValues.firstObject]];
    }else   // 多条数据
    {
        // 排序
        NSArray *sortedKeysArray = [params.allKeys sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            NSComparisonResult result = [obj1 compare:obj2 options:NSNumericSearch];
            return result==NSOrderedAscending; // NSOrderedDescending正序 NSOrderedAscending 倒序
        }];
        
        for (NSString *key in sortedKeysArray) {
            
            id obj = [self appendingStringWithValue:params[key]];
            
            if ([sortedKeysArray.firstObject isEqualToString:key])  // 第一个字典内容
            {
                [appendedString appendFormat:@"{%@:%@",key,obj];
            }else if ([sortedKeysArray.lastObject isEqualToString:key])     // 最后一个内容
            {
                [appendedString appendFormat:@",%@:%@}",key,obj];
            }
            else      // 中间字典内容(非首个或最后一个)
            {
                [appendedString appendFormat:@",%@:%@",key,obj];
            }
        }
        
    }
    
    return appendedString;
    
}

// 数组转字符串
+ (NSString *)arrayToString:(NSArray *)array
{
    NSMutableString *appendedString = [NSMutableString string];
    
    if (array.count  == 0)    // 空数组
    {
        [appendedString appendString:@"[]"];
    }else if (array.count == 1)   // 单个内容
    {
        [appendedString appendFormat:@"[%@]",[self appendingStringWithValue:array[0]]];
    }else   // 多个内容
    {
        for (id obj in array) {
            if ([array indexOfObject:obj] == 0)
            {
                [appendedString appendFormat:@"[%@",[self appendingStringWithValue:obj]];
            }else if(obj == array.lastObject)
            {
                [appendedString appendFormat:@",%@]",[self appendingStringWithValue:obj]];
            }else
            {
                [appendedString appendFormat:@",%@",[self appendingStringWithValue:obj]];
            }
        }
    }
    
    return appendedString;
}

// 拼接参数
+ (NSString *)appendingStringWithValue:(id)value
{
    NSMutableString *appendedString = [NSMutableString string];
    
    if ([value isKindOfClass:[NSArray class]])  // 拼接数组
    {
        [appendedString appendString:[self arrayToString:value]];
    }else if ([value isKindOfClass:[NSDictionary class]])   // 拼接字典
    {
        [appendedString appendString:[self dictionaryToString:value]];
    }else   // 拼接对象
    {
        [appendedString appendFormat:@"%@",value];
    }
    
    return appendedString;
}


@end
